iT邦幫忙

2026 iThome 鐵人賽

DAY 21
1

day21_title

前言

在上一篇,我們完成了 refresh token 以及 jwt 的實作
接下來我們要把一切都接起來,整合我們在系統裡常見的幾個實作
註冊,登入,登出,以及刷新 token (Reuse Detection)的最上層實作
並且我們把 API 接起來,然後完美的完成認證系統的小專案

建立所有路由對應的 檔案以及 function

我們統一在 ./src/routes 的資料夾內,如果有需要練習的讀者,
記得要把先前專案的東西都放進來,細節我就不加贅述了

[補充說明]:
可能有些人對程式方面有 clean architecture 方面有特別要求
因此會看不慣我把 sql 全部統合在一起,因為這裡主要是 demo 用途,所以
無論,註冊,登入等擺在一起是為了好給讀者可以一次閱讀到底

我目前把專案放在 github上了,基本上歡迎研究取用

怕把程式碼在這裡貼太多,淪為流水帳,想知詳情的部分,可以看我的 github 連結
我們這裡大概用流程圖以及決策的方式解釋

註冊

在這裡註冊有幾個要點,除了驗證以外,
我們要把使用者註冊的訊息存到 db 那我們這裡用 bun sqlite 演示
這是註冊的基本

這裡要思考的決策為

註冊流程圖

程式碼我提供在 github: 註冊

登入

登入的重點不外乎就是要驗證帳密,有的話就拿到 jwt token 以及 refreshToken 就放行

登入流程圖

程式碼我提供在 github: 登入

登出

登出不外乎就是要清掉 refreshToken 並且把對應的 cookies Max age 設為 0

登出流程圖

程式碼我提供在 github: 登出

刷新 token

這裏是執行 rotate token 的做法

刷新 token 流程圖

程式碼我提供在 github: 輪替 token

middleware

我們這裡要建立 middleware 去驗證 token

我們建立 ./src/middleware/authenticate.ts

這段 code 比較幾單我直接提供,基本上就是擋住沒有提供token 或過期的路由

如果要找對應在 github : middleware

import { verifyAccessToken } from '../jwt';

export interface AuthenticateResult {
  user_id: string
  email: string
}

export const authenticate = async (req: Request): Promise<AuthenticateResult | Response> => {
  const auth = req.headers.get('authorization');
  if (auth === null)
    return Response.json({
      error: '需要授權'
    }, { status: 401 });
  if (!auth.startsWith('Bearer '))
    return Response.json({
      error: '格式錯誤 Authorization'
    }, { status: 401 });

  return Promise.try(() => verifyAccessToken(auth.slice(7)))
    .then((payload) => ({ user_id: payload.sub, email: payload.email }))
    .catch(() => Response.json({ error: 'token 無效或是過期' }, { status: 401 }));
}

組裝成路由

最後我們把對應的都組裝起來

import { handleRegister } from './routes/register'
import { handleLogin } from './routes/login'
import { handleLogout } from './routes/logout'
import { handleRefresh } from './routes/refresh'
import { authenticate } from './middleware/authenticate'

Bun.serve({
  port: 3000,
  routes: {
    "/api/auth/register": { POST: handleRegister },
    "/api/auth/login": { POST: handleLogin },
    "/api/auth/logout": { POST: handleLogout },
    "/api/auth/refresh": { POST: handleRefresh },
    "/api/sample": {
      GET: async (req: Request): Promise<Response> => {
        const result = await authenticate(req);
        if (result instanceof Response)
          return result;
        const { user_id, email } = result;
        return Response.json({ userId: user_id, email });
      }
    },
  }
});

小提醒!! : 當然我們可以用前面的 Elysia 去實作,那我們這個只用 jose
其他都靠 bun 的威能就可以實現,如果想用 Elysia 去練習也是沒問題的!

結語

到這裡,我們把 JWT + Session 的認證系統從底層機制到路由整合,
完整地串了一遍:註冊、登入、登出、以及帶有 Reuse Detection 的 refresh token 輪替,全部都掛上了實際可以動的 API。
如果你是跟著這系列一步步做下來的讀者,現在手上應該已經有一個「五臟俱全」、
可以直接拿去串接前端或是當作專案骨架的認證系統了。

不過這是比較簡單的版本,關於 Oauth, RBAC, ABAC ,以及 RateLimit 暴力破解等的實作可以弄得更複雜一些,
不過我們的主題基本上圍繞在 bun 上面,搞太複雜也沒意思,等有機會再深度展示這些


上一篇
認證系統實作:JWT + Session 在 Bun 中的最佳實踐(中篇)
下一篇
前端整合:Bun + React + Vite 的開發工作流以及前端測試
系列文
不只是快 —— Bun 30 天:從底層架構、全套工具鏈到生產部署24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言